import time
from pywinauto import Desktop
from pywinauto.findwindows import ElementNotFoundError

from tools.logger import log_error, log_info


class QueryAssertion:
    """
    封装【条码关联系统-关联查询】窗口中【查询】操作的断言逻辑。
    依据：成功时无弹窗；失败时出现 '条码关联系统-提示' 弹窗，提取其内容。
    """

    @staticmethod
    def _find_popup_dialog(timeout=5):
        """查找顶级提示弹窗"""
        desktop = Desktop(backend="win32")
        dialog = desktop.window(title="条码关联系统-提示")
        if dialog.exists(timeout=timeout):
            dialog.wait('visible', timeout=timeout)
            return dialog
        return None

    @staticmethod
    def _get_dialog_message(dialog):
        """通过 auto_id='Tiplbl' 精准获取提示文本"""
        try:
            tip_label = dialog.child_window(auto_id="Tiplbl")
            tip_label.wait('visible', timeout=3)
            text = tip_label.window_text().strip()
            return text
        except Exception as e:
            raise RuntimeError(f"❌ 无法通过 auto_id='Tiplbl' 获取弹窗文本: {e}")

    @staticmethod
    def _close_dialog(dialog):
        """关闭弹窗"""
        try:
            ok_btn = dialog.child_window(title='确定', auto_id="okbtn")
            ok_btn.wait('visible', timeout=2)
            ok_btn.click_input()
            time.sleep(0.5)
            log_info("✅ 已点击【确定】关闭弹窗")
        except Exception as e:
            log_error(f"⚠️ 关闭弹窗失败: {e}")
            try:
                dialog.close()
            except ElementNotFoundError:
                pass

    @staticmethod
    def assert_query_success(timeout=5):
        """断言查询成功：无弹窗"""
        popup = QueryAssertion._find_popup_dialog(timeout=timeout)
        if popup:
            msg = QueryAssertion._get_dialog_message(popup)
            QueryAssertion._close_dialog(popup)
            log_error(f"❌ 查询失败！弹窗提示: {msg}")
            raise AssertionError(f"查询未成功，弹窗提示: {msg}")
        log_info("✅ 查询成功！未出现错误弹窗")

    @staticmethod
    def assert_query_failure(expected_reason=None, timeout=5):
        """断言查询失败：应出现弹窗，并可选验证原因"""
        popup = QueryAssertion._find_popup_dialog(timeout=timeout)
        if not popup:
            raise AssertionError("❌ 预期查询失败但未出现提示弹窗")

        full_text = QueryAssertion._get_dialog_message(popup)
        log_info("🟡 检测到提示弹窗，符合预期")
        log_info(f"📋 弹窗提示内容: {full_text}")

        # 失败关键词映射
        failure_types = {
            "not_found": ["未查询到", "无测试记录", "未找到", "未绑定", "条码不能为空"],
            "format_error": ["条码格式不正确", "条码长度不正确", "非法字符", "不合法"],
            "mismatch": ["工单号不匹配", "项目号不匹配", "不一致", "不属于当前工单"],
            "already_unbound": ["已解绑", "无需解绑", "不允许重复解绑"],
            "general_failure": ["失败", "错误", "异常", "不允许", "操作无效", "系统异常"]
        }

        # 识别实际失败类型
        matched_type = None
        for key, keywords in failure_types.items():
            if any(kw in full_text for kw in keywords):
                matched_type = key
                break
        log_info(f"🔍 识别到失败类型: {matched_type or '未知'}")

        # 验证预期原因
        if expected_reason:
            if expected_reason not in failure_types:
                raise ValueError(f"不支持的 expected_reason: {expected_reason}")
            if not any(kw in full_text for kw in failure_types[expected_reason]):
                QueryAssertion._close_dialog(popup)
                raise AssertionError(
                    f"❌ 预期失败类型 '{expected_reason}'，但实际提示不匹配。\n实际: {full_text}"
                )

        QueryAssertion._close_dialog(popup)
        log_info("✅ 断言通过！查询失败（符合预期）")